from datetime import datetime
from beancount.core.data import Transaction, Posting, Amount
from beancount.core.number import Decimal
from beancount.parser import printer  # Added printer import
from typing import List, Tuple
from beancount.loader import load_file
from beancount.core import getters
import os

def validate_accounts(postings: List[Tuple[str, float, str]], ledger_file: str) -> tuple:
    """
    验证交易中的科目是否在账套中存在
    
    Args:
        postings: 会计分录列表
        ledger_file: 账套文件路径
    Returns:
        tuple: (是否验证通过, 错误信息, 现有账户列表)
    """
    try:
        # 加载账套文件
        entries, errors, options = load_file(ledger_file)
        if errors:
            return False, f"账套文件存在错误: {errors}", []
            
        # 获取所有已定义的账户
        accounts = getters.get_accounts(entries)
        
        # 验证每个科目是否存在
        missing_accounts = []
        for account, _, currency in postings:
            if account not in accounts:
                missing_accounts.append((account, currency))
        
        if missing_accounts:
            missing_info = ", ".join([f"{account}({currency})" for account, currency in missing_accounts])
            return False, f"科目不存在: {missing_info}", list(accounts)
        
        return True, "", list(accounts)
        
    except Exception as e:
        error_message = f"验证科目失败: {e}"
        print(error_message)
        return False, error_message, []

# 修改create_transaction函数，添加科目验证
def create_transaction(
    date: str,
    description: str,
    postings: List[Tuple[str, float, str]],
    ledger_file: str,  # 新增参数
    narration: str = "",
    tags: set = None,
    meta: dict = None
) -> Transaction:
    """
    创建会计凭证（交易记录）并写入文件
    
    Args:
        date: 交易日期，格式 YYYY-MM-DD
        description: 交易描述
        postings: 会计分录列表
        ledger_file: 账套文件路径
        narration: 详细说明
        tags: 标签集合
        meta: 元数据字典
    """
    # 验证科目是否存在
    is_valid, error_message, existing_accounts = validate_accounts(postings, ledger_file)
    if not is_valid:
        # 构建详细的错误信息，包括缺失的账户和现有账户列表
        missing_accounts = []
        for account, _, currency in postings:
            if account not in existing_accounts:
                missing_accounts.append((account, currency))
        
        raise ValueError({
            "message": error_message,
            "existing_accounts": existing_accounts,
            "missing_accounts": missing_accounts
        })
        
    if date is None:  # Changed from start_date to date
        date = datetime.now().date()
    else:
        date = datetime.strptime(date, "%Y-%m-%d").date()
    
    # 创建分录列表
    final_postings = []
    for account, amount, currency in postings:
        posting = Posting(
            account=account,
            units=Amount(Decimal(str(amount)), currency),
            cost=None,
            price=None,
            flag=None,
            meta=None
        )
        final_postings.append(posting)
    
    # 创建交易记录
    transaction = Transaction(
        meta=meta or {},
        date=date,
        flag="*",
        payee=None,
        narration=description,
        tags=tags or set(),
        links=set(),
        postings=final_postings
    )
    
    # 将交易记录写入文件
    with open(ledger_file, 'a', encoding='utf-8') as f:
        f.write('\n' + printer.format_entry(transaction) + '\n')
    
    return transaction

# 使用示例更新
if __name__ == "__main__":
    ledger_file = "c:\\code\\acccount\\main.beancount"
    
    postings = [
        ("Assets:ITCompany:Bank", 50000, "CNY"),
        ("Income:ITCompany:ProjectIncome", -50000, "CNY")
    ]
    
    try:
        transaction = create_transaction(
            date="2025-03-20",
            description="收到XX公司项目开发款",
            postings=postings,
            ledger_file=ledger_file,
            narration="项目第一期款项",
            tags={"project", "dev"}
        )
        print(f"✓ 交易记录已创建并写入文件: {ledger_file}")
        
    except Exception as e:
        print(f"创建凭证错误: {e}")